Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement event ownership #423

Merged
merged 11 commits into from
Dec 14, 2023
Merged

Implement event ownership #423

merged 11 commits into from
Dec 14, 2023

Conversation

r-c-n
Copy link

@r-c-n r-c-n commented Dec 1, 2023

Introduction

This PR features a first basic step towards proper event filtering and handling. User ownership data is added to events and subscriptions, and the ownership is checked by default in "listen" and "unsubscribe" operations.

Functional changes

Changes to PublishEvent and Subscription

The Subscription model now includes a user field to store the username associated to the subscription (ie. the "owner"). NOTE: This assumes that usernames are unique.

The PublishEvent model was simplified and the processing of events through the publish endpoint now includes an implicit definition of the event owner and it allows overriding the default "type" and "source" attributes (if that's ever needed, if not we can remove this) and adding other extra attributes freely. From a users perspective, the only mandatory field in the request is data (dict). Any other extra attributes can be defined in attributes (dict).

Example payload for a publish request with a custom extra attribute: '{"data" : {"my_event_id" : 1}, "attributes" : {"level" : "critical"}}'. The owner attribute is added automatically by the server.

Listening for events now receives only those published by the same user and "anonymous" events

By default, a request to the listen endpoint will only receive events owned by the same user that's listening. Anonymous events (ie. events that don't define an owner, such as keepalive events) are still received by all subscribers.
(See "Disabling user-checking on event listening" below for alternatives).

Users can unsubscribe their own subscriptions only

Check user ownership of subscriptions to prevent a user from removing a subscription that another user created.

Ownership of node creation events

All node creation events published by the node and nodes endpoints now have the authenticated request user as the owner, so only this user will receive these events.

Open questions

Better integration of the User handling functionalities into this

This PR is very basic and it doesn't make full use of the user management capabilities that are currently implemented. We may want to make a better use of these capabilities, for example, to do permission and ownership checks based on user groups.

Disabling user-checking on event listening

Even if we want to keep and check the ownership of a subscription (to let only the owner unsubscribe, for instance), there'll probably be use cases where a privileged user might want to implement a monitor or a debugger that can listen to any arbitrary event regardless of its owner. This can be implemented by using an additional Subscription attribute to define its type ("regular-user subscription", "monitor-mode subscription", etc)

Features based on user capabilities

Certain (future) features could be made available only to certain users or user groups, such as admins.

Server-side event filtering

Currently, events are filtered in the client side by helper functions. The same thing can be done in the server side, moving the processing to the server and hiding unwanted data from ever reaching the clients. Would this be useful or desirable?

@r-c-n r-c-n force-pushed the event-ownership branch 7 times, most recently from b0c6cb0 to 33d0a80 Compare December 1, 2023 10:13
@r-c-n r-c-n marked this pull request as ready for review December 1, 2023 10:17
@JenySadadia
Copy link
Collaborator

Thanks for the proposed changes. The PR looks pretty useful.

Disabling user-checking on event listening
Even if we want to keep and check the ownership of a subscription (to let only the owner unsubscribe, for instance), there'll probably be use cases where a privileged user might want to implement a monitor or a debugger that can listen to any arbitrary event regardless of its owner. This can be implemented by using an additional Subscription attribute to define its type ("regular-user subscription", "monitor-mode subscription", etc)

I don't think any additional subscription field is required here. If the user omits owner field in the subscription filter, the user should be able to receive all the events regardless of its owner.

api/main.py Show resolved Hide resolved
api/pubsub.py Show resolved Hide resolved
api/pubsub.py Outdated Show resolved Hide resolved
api/models.py Outdated Show resolved Hide resolved
api/pubsub.py Outdated Show resolved Hide resolved
@r-c-n
Copy link
Author

r-c-n commented Dec 4, 2023

Thanks for the proposed changes. The PR looks pretty useful.

Thanks for reviewing.

Disabling user-checking on event listening
Even if we want to keep and check the ownership of a subscription (to let only the owner unsubscribe, for instance), there'll probably be use cases where a privileged user might want to implement a monitor or a debugger that can listen to any arbitrary event regardless of its owner. This can be implemented by using an additional Subscription attribute to define its type ("regular-user subscription", "monitor-mode subscription", etc)

I don't think any additional subscription field is required here. If the user omits owner field in the subscription filter, the user should be able to receive all the events regardless of its owner.

Not with the changes in this PR, that's a fundamental difference and it's worth it to discuss what's the most reasonable approach.

Currently, there's no server-side filtering of events whatsoever, so all the filtering is done by clients in the way you explained. That means that every client will receive all events if they didn't specify any subscription filter, if I understood correctly.

In previous conversations, the consensus was that the server should provide the necessary filtering to avoid flooding the clients and (IMO) to provide a basis for a more secure event dispatching. For example, in the future we might want to implement private events that will be sent only to certain authorized users.

The key feature in this PR is event/subscription ownership. When a client creates a subscription, it's automatically set as the owner of it. Then, events sent through the publish endpoint (and also the node/nodes endpoints) are also "owned" by the authorized user that initiates them. By default, I made it so that a subscribed user will only receive events generated by him/her or anonymous events (keepalive beeps). This was to address @nuclearcat 's concerns that users were getting flooded by checkout events, but this is only one solution and it doesn't need to be this way. If you think there's a more reasonable approach to this, I'd like to know it.

api/pubsub.py Outdated Show resolved Hide resolved
@r-c-n r-c-n force-pushed the event-ownership branch 2 times, most recently from b462201 to 7704982 Compare December 5, 2023 16:52
@r-c-n
Copy link
Author

r-c-n commented Dec 5, 2023

Btw, pylint is failing because:

api/pubsub.py:11:0: W0404: Reimport 'json' (imported line 9) (reimported)

But that's not true AFAICT?

@JenySadadia
Copy link
Collaborator

Btw, pylint is failing because:

api/pubsub.py:11:0: W0404: Reimport 'json' (imported line 9) (reimported)

But that's not true AFAICT?

I see aioredis on the mentioned line. Could you please rebase the PR as we removed that package and used redis instead? Maybe that would solve the issue if it is due to aioredis.

Ricardo Cañuelo added 2 commits December 11, 2023 12:58
Simplify the PublishEvent model and define it so that only the "data"
field is mandatory. "type" and "source" are optional and the API fills
them by default if undefined. "attributes" is an optional dict to
specify additional event attributes.

An additional attribute ("owner") will be automatically added by the API
when necessary.

Signed-off-by: Ricardo Cañuelo <[email protected]>
This field will associate a Subscription to the user that requested
it and will be used later to do server-side filtering of events based
on the event owner.

Signed-off-by: Ricardo Cañuelo <[email protected]>
@r-c-n r-c-n force-pushed the event-ownership branch 3 times, most recently from f84e47d to 9b0b26a Compare December 11, 2023 13:05
Keep track of the Subscription object associated to each subscription id
so that it can be retrieved later on "listen" operations. This will
allow the API to check for the Subscription "user" and filter out
unwanted messages if necessary.

Signed-off-by: Ricardo Cañuelo <[email protected]>
Ricardo Cañuelo added 5 commits December 11, 2023 14:20
Let the caller specify optional attributes or no attributes at all. Fill
in 'type' and 'source' with default values if undefined.

Signed-off-by: Ricardo Cañuelo <[email protected]>
If the event specifies an owner, send it only to the subscriptions
created by that user.

Signed-off-by: Ricardo Cañuelo <[email protected]>
…ttributes

Sync the publish endpoint to the current implementation of
pubsub.publish_cloudevent().

Add a 'owner' attribute in the event to save the username of the
authenticated request user.

Signed-off-by: Ricardo Cañuelo <[email protected]>
@r-c-n r-c-n force-pushed the event-ownership branch 2 times, most recently from da20c80 to f14ef50 Compare December 11, 2023 13:26
Ricardo Cañuelo added 2 commits December 13, 2023 12:20
Let a user unsubscribe only from his/her own subscriptions. Prior to
this change, anyone could unsubscribe anybody else from whatever active
subscription.

Signed-off-by: Ricardo Cañuelo <[email protected]>
Copy link
Collaborator

@JenySadadia JenySadadia left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested OK locally.
Let's wait for the staging results before merging.

@JenySadadia
Copy link
Collaborator

Tested OK on staging.

@JenySadadia JenySadadia added this pull request to the merge queue Dec 14, 2023
Merged via the queue into kernelci:main with commit 7643078 Dec 14, 2023
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add user parameter when subscribing
2 participants